/************************************************************************************************************************************************************
 *                          DESENVOLVEDORES: Paulo Costa; Diogo Oliveira; Iara Fernanda; Mariana Souza
 *                          ORIENTADOR e CO-DESENVOLVEDOR: Prof.Dr. Eraldo Pereira Marinho
 *
 *                                                           ARQUIVO: lexer.c
 *
 ************************************************************************************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tokens.h"
#include "keywords.h"
#include "lexer.h"

FILE *tape;
char lexeme[256];
int lookahead;
int line=1;
int i;

/*
 * função que pula espaços vazios e comentarios e incrementa o numero de linhas
 */
void
skipspaces()
{
  while(isspace(lookahead = getc(tape))){
	if(lookahead == '\n')line++;
	
  }  
  if(lookahead == '{'){
    while ((lookahead = getc(tape)) != '}'){
      if(lookahead == '\n') line++;
    }
  }else{
    ungetc(lookahead, tape);
  }
}

token_t 
isID(FILE *tape){
  int i = 0;
  if (isalpha(lexeme[i] =toupper(lookahead))) {
    token_t	token;
    while (isalnum(lexeme[++i] = toupper(getc(tape))));
      ungetc(lexeme[i], tape);
      lexeme[i]=0;
      fprintf(stderr,"lexeme= %s\n", lexeme);

      if (token=iskeyword(lexeme))
		return token;
      else
		return ID;
    }
    return 0;
}

void
assign(void){ 
}

int
isOPLUS(FILE * tape){
  
  	switch (lookahead) {
	case '+':
	case '-':
      return OPLUS;
      break;
    default:
      return 0;
  }
}

int
isOTIMES(FILE * tape){
  int head = getc(tape);
  switch (head) {
    case '*':
    case '/':
      return OTIMES;
      break;
  }
  ungetc(head,tape);
  return 0;
}

int
isHEXA(FILE * tape){
  int head;
  if(isdigit(head  = getc(tape)) || ('a' <= tolower(head) && tolower(head) <= 'f')){
    while(isdigit(head  = getc(tape)) || ('a' <= tolower(head) && tolower(head) <= 'f'));
    ungetc(head,tape);
    return 1;  
  }
  else{
    ungetc(head,tape);
    return 0;
  }    
}

int
isOCTA(FILE * tape){
  int head;
  if((head  = getc(tape)) >= '0'  && head  <= '7' ){
    while((head  = getc(tape)) >= '0'  && head  <= '7' );
    ungetc(head,tape);
    return 1;
  }
  else{
    ungetc(head,tape); 	
    return 0;
  }
}

/*
 *  UINT -> [1-9][0-9]* | '0'
 */
int
isUINT(){
  int i = 0;
  lexeme[i] = lookahead;
  if(isdigit(lexeme[i])) {
    if(lexeme[i] == '0') {
      lexeme[1] = 0;
      return UINT;
    }
    while (isdigit(lexeme[++i] = getc(tape)));
    ungetc(lexeme[i], tape);
    lexeme[i] = 0;
    return UINT;
  }
  return 0;
}

/*
 * FLOAT = UINT ('.' digit* EXPNotation? | EXPNotation) | '.' digit+ EXPNotation?
 * ExpNotation = 'E' ('+'|'-')? digit+
 * 
 *
 * Para apoio a mesma expressão, mas com outras representações (está suprimida a expressão para frac)
 * fp = frac exp ? | uint exp
 *    = (uint '.' [0-9]* | '.'[0-9]+) exp ? | uint exp
 *    = uint ('.' [0-9]* exp ? | exp) | '.' [0-9]+ exp ?
 */
int
isFLOAT(){
  int i = 0;
  if(isUINT(lexeme[i]=lookahead)){
    switch(lookahead){
      case '.':{
	while(isdigit(lexeme[++i] = getc(tape)));
	ungetc(lexeme[i], tape);
	if((lexeme[i] = getc(tape)) == 'E'){
	  ++i;    /* E notation format check */
	  if(lexeme[i] == '+' || lexeme[i] == '-'){
	    lexeme[i] = getc(tape);
	  }
	  if(isdigit(lexeme[i] = getc(tape))){
	    while(isdigit(lexeme[++i] = getc(tape)));
	    ungetc(lexeme[i], tape);
	  }
	  else{
	    ungetc(lexeme[i], tape);
	    fprintf(stderr, "\nIlegal exponential notation\n");
	    return -2;
	  }       /* If the E notation was correct the flow continue here */
	  return FLOAT;
	}
	else{
	  return FLOAT;
	}
      }
      case 'E':{
	++i;    /* E notation format check */
	if(lexeme[i] == '+' || lexeme[i] == '-'){
	  lexeme[i] = getc(tape);
	}
	if(isdigit(lexeme[i] = getc(tape))){
	  while(isdigit(lexeme[++i] = getc(tape)));
	   ungetc(lexeme[i], tape);
	}
	else{
	  ungetc(lexeme[i], tape);
	  fprintf(stderr, "\nIlegal exponential notation\n");
	  return -2;
	}       /* If the E notation was correct the flow continue here */
	return FLOAT;
      }
      default:
	ungetc(lexeme[i], tape);
	return UINT;
    }
  }
  if(lexeme[i] = lookahead == '.'){
    fprintf(stderr,"\nEntrou NO PONTO\n");
    if(isdigit(lexeme[++i] = getc(tape))){
      fprintf(stderr,"Eh digito isFLOAT\n"); 
      while(isdigit(lexeme[++i] = getc(tape)));
      ungetc(lexeme[i], tape);
      if((lexeme[i] = getc(tape)) == 'E'){
	++i;    /* E notation format check */
	if(lexeme[i] == '+' || lexeme[i] == '-'){
	  lexeme[i] = getc(tape);
	}
	if(isdigit(lexeme[i] = getc(tape))){
	  while(isdigit(lexeme[++i] = getc(tape)));
	}
	else{
	  ungetc(lexeme[i], tape);
	  fprintf(stderr, "\nIlegal exponential notation\n");
	  return -2;
	}      /* If the E notation was correct the flow continue here */
	return FLOAT;
      }
      else{
	return FLOAT;
      }
    }
  }
  return 0;
}

int
isNUM(void){
  
  int i = 0;
  if (isUINT(lexeme[i]=lookahead)) {
    if (lexeme[i] == '.') {
      while (isdigit(lexeme[++i] = getc(tape)));
      ungetc(lexeme[i], tape);
      lexeme[i] = 0;
      isFLOAT();
      return FLOAT;
    }
    ungetc(lexeme[i], tape);
    lexeme[i] = 0;
    if (isFLOAT())
      return FLOAT;
    return UINT;
  }
  if (lexeme[i] == '.') {
    
    if (isdigit(lexeme[++i] = getc(tape))) {
      while (isdigit(lexeme[++i] = getc(tape)));
      ungetc(lexeme[i], tape);
      lexeme[i] = 0;
      isFLOAT();
      return FLOAT;
    }
    ungetc(lexeme[i--], tape);
    ungetc('.', tape);
    return 0;
  }
  return 0;
}

int
isRELOP(void){
  fprintf(stderr,"Entrou isRELOP\n");
  int i = 0;
  switch (lexeme[i] = getc(tape)){
    case '<':
      if ((lexeme[++i] = getc(tape)) == '>')
      {
	strcpy(lexeme, "<>");
	return RELOP;
      }
      else if (lexeme[i] == '='){
	strcpy(lexeme, "<=");
	return RELOP;
      }
      ungetc(lexeme[i], tape);
      strcpy(lexeme, "<");
      return RELOP; 
    case '>':
      if ((lexeme[++i] = getc(tape)) == '=')
      {
	strcpy(lexeme, ">=");
	return RELOP;
      }
      ungetc(lexeme[i], tape);
      strcpy(lexeme, ">");
      return RELOP;
    case '=':
      lexeme[i+1]=0;
      return RELOP;
    default:
      ungetc(lexeme[i], tape);
      return 0;
  }
}

int
isASSGNMT(void){
  int i = 0;
  if((lexeme[i]=lookahead)==':'){
      if((lexeme[++i]=getc(tape))=='='){
      lexeme[i] = 0;
      return ASSGNMT;
    }
    else{
      ungetc(lexeme[i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  }
  return 0;
}

int
isLEQ(void){
   fprintf(stderr,"Entrou isLEQ\n");
  int i = 0;
  if((lexeme[i++]=getc(tape))=='<')
  {
    if((lexeme[i++]=getc(tape))=='=')
    {
      lexeme[i] = 0;
      return LEQ;
    }
    ungetc(lexeme[--i],tape);
    lexeme[i]=0;
    return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

int
isNEQ(void){
   fprintf(stderr,"Entrou isNEQ\n");
  int i = 0;
  if((lexeme[i++]=getc(tape))=='<')
  {
    if((lexeme[i++]=getc(tape))=='>')
    {
      lexeme[i] = 0;
      return NEQ;
    }
    ungetc(lexeme[--i],tape);
    lexeme[i]=0;
    return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

int
isGEQ(void){
  fprintf(stderr,"Entrou isGEQ\n");
  int i = 0;
  if((lexeme[i++]=getc(tape))=='>')
  {
    if((lexeme[i++]=getc(tape))=='=')
    {
      lexeme[i] = 0;
      return GEQ;
    }
    ungetc(lexeme[--i],tape);
    lexeme[i]=0;
    return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

/* 
 * PARSER INTERFACE
 */

int
gettoken(FILE * tape){

  token_t	token=0;
    
  skipspaces();

  lookahead = getc(tape);
 
  
  
    /* test which automaton can acept */
  if (token = isID(tape)){
    printf("Token ID= %d\n", token);
    return token;
  }
  
  if (token = isNUM()){
    fprintf(stderr,"Token NUM= %d\n", token);
    return token;
  }
  if (token = isFLOAT(tape)){
    fprintf(stderr,"Token FLOAT= %d\n", token);
    return token;
  }
  if (token = isOPLUS(tape)){
    fprintf(stderr,"Token OPLUS= %d\n", token);
    return token;
  }
  if (token = isOTIMES(tape)){
    fprintf(stderr,"Token OTIMES= %d\n", token);
    return token;
  }
  if (token = isLEQ()){
    fprintf(stderr,"Token LEQ= %d\n", token);
    return token;
  }
  if (token = isGEQ()){
    fprintf(stderr,"GEQ= %d\n", token);
    return token;
  }
  if (token = isNEQ()){
    fprintf(stderr,"NEQ= %d\n", token);
    return token;
  }
  if (token = isASSGNMT()){
    fprintf(stderr,"ASSGNM= %d\n", token);
    return token;
  }
  
  lexeme[1] = 0;
  return lookahead;
}
    
void 
match(int expected){
  printf("\nInternalTest - Entrou na funcao match\n");
  fprintf(stderr,"lookahead= %d\n",lookahead);
  fprintf(stderr,"expected= %d\n\n",expected);
  if (expected == lookahead){
    fprintf(stderr,"Aceitou = %d\n",expected);
    lookahead = gettoken(tape);
  }else{
    fprintf(stderr, "token mismatch: Line %d: %d expected %d\naborting...\n",
	    line, lookahead,expected);
    exit(-1);
  }
}